import _mergeJSXProps from "@vue/babel-helper-vue-jsx-merge-props";
import {deepClone} from '../utils/deep-clone';
import {createNamespace, isObj} from '../utils';
import {range} from '../utils/format/number';
import {preventDefault} from '../utils/dom/event';
import {TouchMixin} from '../mixins/touch';

var DEFAULT_DURATION = 200; // 惯性滑动思路:
// 在手指离开屏幕时，如果和上一次 move 时的间隔小于 `MOMENTUM_LIMIT_TIME` 且 move
// 距离大于 `MOMENTUM_LIMIT_DISTANCE` 时，执行惯性滑动

var MOMENTUM_LIMIT_TIME = 300;
var MOMENTUM_LIMIT_DISTANCE = 15;

var _createNamespace = createNamespace('picker-column'),
    createComponent = _createNamespace[0],
    bem = _createNamespace[1];

function getElementTranslateY(element) {
    var style = window.getComputedStyle(element);
    var transform = style.transform || style.webkitTransform;
    var translateY = transform.slice(7, transform.length - 1).split(', ')[5];
    return Number(translateY);
}

function isOptionDisabled(option) {
    return isObj(option) && option.disabled;
}

export default createComponent({
    mixins: [TouchMixin],
    props: {
        valueKey: String,
        allowHtml: Boolean,
        className: String,
        itemHeight: Number,
        defaultIndex: Number,
        swipeDuration: Number,
        visibleItemCount: Number,
        initialOptions: {
            type: Array,
            default: function _default() {
                return [];
            }
        }
    },
    data: function data() {
        return {
            offset: 0,
            duration: 0,
            options: deepClone(this.initialOptions),
            currentIndex: this.defaultIndex
        };
    },
    created: function created() {
        if (this.$parent.children) {
            this.$parent.children.push(this);
        }

        this.setIndex(this.currentIndex);
    },
    mounted: function mounted() {
        this.bindTouchEvent(this.$el);
    },
    destroyed: function destroyed() {
        var children = this.$parent.children;

        if (children) {
            children.splice(children.indexOf(this), 1);
        }
    },
    watch: {
        defaultIndex: function defaultIndex() {
            this.setIndex(this.defaultIndex);
        }
    },
    computed: {
        count: function count() {
            return this.options.length;
        },
        baseOffset: function baseOffset() {
            return this.itemHeight * (this.visibleItemCount - 1) / 2;
        }
    },
    methods: {
        onTouchStart: function onTouchStart(event) {
            this.touchStart(event);

            if (this.moving) {
                var translateY = getElementTranslateY(this.$refs.wrapper);
                this.offset = Math.min(0, translateY - this.baseOffset);
                this.startOffset = this.offset;
            } else {
                this.startOffset = this.offset;
            }

            this.duration = 0;
            this.transitionEndTrigger = null;
            this.touchStartTime = Date.now();
            this.momentumOffset = this.startOffset;
        },
        onTouchMove: function onTouchMove(event) {
            this.touchMove(event);

            if (this.direction === 'vertical') {
                this.moving = true;
                preventDefault(event, true);
            }

            this.offset = range(this.startOffset + this.deltaY, -(this.count * this.itemHeight), this.itemHeight);
            var now = Date.now();

            if (now - this.touchStartTime > MOMENTUM_LIMIT_TIME) {
                this.touchStartTime = now;
                this.momentumOffset = this.offset;
            }
        },
        onTouchEnd: function onTouchEnd() {
            var _this = this;

            var distance = this.offset - this.momentumOffset;
            var duration = Date.now() - this.touchStartTime;
            var allowMomentum = duration < MOMENTUM_LIMIT_TIME && Math.abs(distance) > MOMENTUM_LIMIT_DISTANCE;

            if (allowMomentum) {
                this.momentum(distance, duration);
                return;
            }

            var index = this.getIndexByOffset(this.offset);
            this.duration = DEFAULT_DURATION;
            this.setIndex(index, true); // compatible with desktop scenario
            // use setTimeout to skip the click event triggered after touchstart

            setTimeout(function () {
                _this.moving = false;
            }, 0);
        },
        onTransitionEnd: function onTransitionEnd() {
            this.stopMomentum();
        },
        onClickItem: function onClickItem(index) {
            if (this.moving) {
                return;
            }

            this.duration = DEFAULT_DURATION;
            this.setIndex(index, true);
        },
        adjustIndex: function adjustIndex(index) {
            index = range(index, 0, this.count);

            for (var i = index; i < this.count; i++) {
                if (!isOptionDisabled(this.options[i])) return i;
            }

            for (var _i = index - 1; _i >= 0; _i--) {
                if (!isOptionDisabled(this.options[_i])) return _i;
            }
        },
        getOptionText: function getOptionText(option) {
            return isObj(option) && this.valueKey in option ? option[this.valueKey] : option;
        },
        setIndex: function setIndex(index, userAction) {
            var _this2 = this;

            index = this.adjustIndex(index) || 0;
            this.offset = -index * this.itemHeight;

            var trigger = function trigger() {
                if (index !== _this2.currentIndex) {
                    _this2.currentIndex = index;

                    if (userAction) {
                        _this2.$emit('change', index);
                    }
                }
            }; // trigger the change event after transitionend when moving


            if (this.moving) {
                this.transitionEndTrigger = trigger;
            } else {
                trigger();
            }
        },
        setValue: function setValue(value) {
            var options = this.options;

            for (var i = 0; i < options.length; i++) {
                if (this.getOptionText(options[i]) === value) {
                    return this.setIndex(i);
                }
            }
        },
        getValue: function getValue() {
            return this.options[this.currentIndex];
        },
        getIndexByOffset: function getIndexByOffset(offset) {
            return range(Math.round(-offset / this.itemHeight), 0, this.count - 1);
        },
        momentum: function momentum(distance, duration) {
            var speed = Math.abs(distance / duration);
            distance = this.offset + speed / 0.002 * (distance < 0 ? -1 : 1);
            var index = this.getIndexByOffset(distance);
            this.duration = this.swipeDuration;
            this.setIndex(index, true);
        },
        stopMomentum: function stopMomentum() {
            this.moving = false;
            this.duration = 0;

            if (this.transitionEndTrigger) {
                this.transitionEndTrigger();
                this.transitionEndTrigger = null;
            }
        },
        genOptions: function genOptions() {
            var _this3 = this;

            var h = this.$createElement;
            var optionStyle = {
                height: this.itemHeight + "px"
            };
            return this.options.map(function (option, index) {
                var text = _this3.getOptionText(option);

                var disabled = isOptionDisabled(option);
                var data = {
                    style: optionStyle,
                    attrs: {
                        role: 'button',
                        tabindex: disabled ? -1 : 0
                    },
                    class: ['van-ellipsis', bem('item', {
                        disabled: disabled,
                        selected: index === _this3.currentIndex
                    })],
                    on: {
                        click: function click() {
                            _this3.onClickItem(index);
                        }
                    }
                };

                if (_this3.allowHtml) {
                    data.domProps = {
                        innerHTML: text
                    };
                }

                return h("li", _mergeJSXProps([{}, data]), [_this3.allowHtml ? '' : text]);
            });
        }
    },
    render: function render() {
        var h = arguments[0];
        var wrapperStyle = {
            transform: "translate3d(0, " + (this.offset + this.baseOffset) + "px, 0)",
            transitionDuration: this.duration + "ms",
            transitionProperty: this.duration ? 'all' : 'none',
            lineHeight: this.itemHeight + "px"
        };
        return h("div", {
            "class": [bem(), this.className]
        }, [h("ul", {
            "ref": "wrapper",
            "style": wrapperStyle,
            "class": bem('wrapper'),
            "on": {
                "transitionend": this.onTransitionEnd
            }
        }, [this.genOptions()])]);
    }
});